package br.puc.casas.ca;

import java.awt.Color;
import java.util.Random;

import org.generation5.bio.CAAgent;
import org.generation5.bio.CellularAutomataLayered;
import org.generation5.util.Gradient;

public class DictyosteliumCA extends CellularAutomataLayered {

	private Random random = new Random();

	public DictyosteliumCA() {
		this(0, 0);
	}

	public DictyosteliumCA(int size_x, int size_y) {
		super(size_x, size_y, DOUBLE_BUFFERING);

		Gradient gradient = new Gradient();
		gradient.addPoint(Color.black);
		gradient.addPoint(new Color(0, 128, 0));
		gradient.addPoint(Color.green);
		gradient.addPoint(Color.yellow);
		gradient.addPoint(Color.white);
		gradient.createGradient();

		setWorldColors(gradient.getGradient());
	}

	@Override
	public void doStep() {
		// Evaporate the pheromone levels
		for (int i = 0; i < getSizeX(); i++) {
			for (int j = 0; j < getSizeY(); j++) {
				setWorldAtRelative(i, j, -1);
				int avg = 0;
				for (int x = i - 1; x < i + 2; x++) {
					for (int y = j - 1; y < j + 2; y++) {
						avg += getWorldAt(x, y);
					}
				}

				setWorldAt(i, j, avg / 9);
			}
		}

		// For each CA, find the strong pheromone level
		for (int i = 0; i < getNumCAs(); i++) {
			CAAgent ca = getCA(i);
			setWorldAtRelative(ca.getX(), ca.getY(), 8);

			int dx = random.nextInt(3) - 1;
			int dy = random.nextInt(3) - 1;
			int world = 0;
			int highest = 16;
			int cx = ca.getX(), cy = ca.getY();
			for (int x = -1; x < 2; x++) {
				for (int y = -1; y < 2; y++) {
					if (x == 0 && y == 0)
						continue;
					if (isCellFree(cx + x, cy + y)) {
						world = getWorldAt(cx + x, cy + y);
						if (world > highest
								|| ((world == highest && Math.random() < 0.5))) {
							highest = world;
							dx = x;
							dy = y;
						}
					}
				}
			}

			moveCARelative(i, dx, dy);
		}

		flipBuffer();
	}

	@Override
	public void init() {
		clearWorld();
		removeAll();

		int num = (int) (caWorld_x * caWorld_y * 0.05);
		for (int i = 0; i < num; i++) {
			int px = random.nextInt(caWorld_x);
			int py = random.nextInt(caWorld_y);
			addAutomaton(px, py, 1);
		}

		setCollisionDetection(true);

		flipBuffer();
	}

}
